package com.xbongbong.saas.analytical.impl;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.xbongbong.i18n.util.I18nMessageUtil;
import com.xbongbong.paas.constant.PaasConstant;
import com.xbongbong.paas.domain.entity.PaasFormEntity;
import com.xbongbong.paas.domain.entity.ext.PaasFormDataEntityExt;
import com.xbongbong.paas.elasticsearch.model.PaasEsModel;
import com.xbongbong.paas.enums.DelEnum;
import com.xbongbong.paas.enums.FlowStatusEnum;
import com.xbongbong.paas.enums.IndexTypeEnum;
import com.xbongbong.paas.enums.PaymentSheetTypeEnum;
import com.xbongbong.paas.help.team.TeamUserHelp;
import com.xbongbong.paas.model.PaasAppModel;
import com.xbongbong.paas.model.PaasFormModel;
import com.xbongbong.paas.pojo.dto.FormDataAddDTO;
import com.xbongbong.paas.pojo.dto.ValidateDataDTO;
import com.xbongbong.paas.toolbox.exception.XbbException;
import com.xbongbong.paas.toolbox.util.Arith;
import com.xbongbong.paas.toolbox.util.BeanUtil;
import com.xbongbong.paas.toolbox.util.CollectionsUtil;
import com.xbongbong.pro.constant.BusinessConstant;
import com.xbongbong.pro.constant.I18nStringConstant;
import com.xbongbong.pro.enums.SaasMarkEnum;
import com.xbongbong.pro.enums.errorcodes.ContractErrorCodeEnum;
import com.xbongbong.pro.enums.errorcodes.RefundErrorCodeEnum;
import com.xbongbong.pro.enums.errorcodes.SystemErrorCodeEnum;
import com.xbongbong.saas.analytical.SaasValidateAnalyticalService;
import com.xbongbong.saas.constant.BasicConstant;
import com.xbongbong.saas.constant.ParameterConstant;
import com.xbongbong.saas.constant.StringConstant;
import com.xbongbong.saas.domain.entity.ext.ContractEntityExt;
import com.xbongbong.saas.enums.SelectProductEnum;
import com.xbongbong.saas.enums.XbbRefTypeEnum;
import com.xbongbong.saas.enums.business.ContractEnum;
import com.xbongbong.saas.enums.business.PaymentEnum;
import com.xbongbong.saas.enums.business.PaymentSheetEnum;
import com.xbongbong.saas.enums.business.RefundEnum;
import com.xbongbong.saas.enums.dictionary.PaymentStatusEnum;
import com.xbongbong.saas.help.SaasProductHelp;
import com.xbongbong.saas.help.SaveFormatHelp;
import com.xbongbong.saas.model.ContractModel;
import com.xbongbong.saas.toolbox.help.FastJsonHelper;
import com.xbongbong.util.ProductUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;

/**
 * @author 吴峰
 * @date 2021/07/15 17:15
 */
@Service("refundAnalyticalServiceImpl")
public class RefundValidateAnalyticalServiceImpl implements SaasValidateAnalyticalService {
    
    private static final Logger LOGGER = LoggerFactory.getLogger(RefundValidateAnalyticalServiceImpl.class);
    
    @Resource
    private TeamUserHelp teamUserHelp;
    @Resource
    private SaasProductHelp saasProductHelp;
    @Resource
    private ContractModel contractModel;
    @Resource
    private PaasEsModel paasEsModel;
    @Resource
    private PaasAppModel paasAppModel;
    @Resource
    private PaymentValidateAnalyticalServiceImpl paymentAnalyticalService;
    @Resource
    private PaasFormModel paasFormModel;
    @Resource
    private PaymentSheetValidateAnalyticalServiceImpl paymentSheetAnalyticalService;

    @Override
    public List<Integer> type() {
        return Arrays.asList(XbbRefTypeEnum.REFUND.getCode());
    }

    @Override
    public void analyticalData(ValidateDataDTO validateDataDTO) throws XbbException {
        beforeSave(validateDataDTO);
        teamUserHelp.beforeVerifyUserTeam(validateDataDTO);
    }
    
    public void beforeSave(ValidateDataDTO validateDataDTO) throws XbbException {
        try {
            JSONObject data = validateDataDTO.getData();
            String corpid = validateDataDTO.getCorpid();
            String serialNo = validateDataDTO.getSerialNo();
            SaveFormatHelp.formatLinkBusiness4Save(data, RefundEnum.CUSTOMER_ID.getAttr(), RefundEnum.CUSTOMER_ID_LINKED_TEXT.getAttr(), RefundEnum.CONTRACT_ID_LINKED_TEXT.getFieldType());
            SaveFormatHelp.formatLinkBusiness4Save(data, RefundEnum.CONTRACT_ID.getAttr(), RefundEnum.CONTRACT_ID_LINKED_TEXT.getAttr(), RefundEnum.CONTRACT_ID_LINKED_TEXT.getFieldType());

            //序列号必填校验
            SaveFormatHelp.batchSaveRequiredCheck(validateDataDTO);
            Long contractId = FastJsonHelper.getLongOrDefaultFromFormData(data, RefundEnum.CONTRACT_ID.getAttr(), 0L);
            ContractEntityExt contractEntityExt = contractModel.getByKey(contractId, corpid);
            if (Objects.isNull(contractEntityExt)) {
                throw new XbbException(ContractErrorCodeEnum.API_ERROR_203001);
            }
            if (Objects.isNull(contractEntityExt.getData())) {
                throw new XbbException(ContractErrorCodeEnum.API_ERROR_203001);
            }

            JSONArray productArray = FastJsonHelper.getJsonArrOrDefaultFromFormData(data,RefundEnum.PRODUCTS.getAttr(),new JSONArray());
            // jxc开启时:查询退货出库产品  jxc关闭时:查询退货合同产品
            Long refundId = validateDataDTO.getDataId();
            validateDataProduct(productArray, corpid, contractId, refundId);
            Double returnAmount = FastJsonHelper.getDoubleOrDefaultFromFormData(data, RefundEnum.RETURN_AMOUNT.getAttr(), 0D);
            if (returnAmount == 0 && productArray.size() == 0) {
                throw new XbbException(RefundErrorCodeEnum.API_ERROR_215024);
            }
            Double refundAmount = FastJsonHelper.getDoubleOrDefaultFromFormData(data, RefundEnum.REFUND_AMOUNT.getAttr(), 0D);
            refundAmountJudgement(corpid, refundAmount, returnAmount, contractId, refundId,serialNo);
            //校验红冲回款单、红冲应收款、红冲作废发票关联的原始单据
            validateFundData(validateDataDTO);
            validateDataDTO.setData(data);
        } catch (XbbException e) {
            throw e;
        }  catch (Exception e) {
            LOGGER.error("refundAnalyticalServiceImpl.beforeSave error", e);
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001);
        }
    }

    /**
     * @description 退货退款的前置校验回款单，应收款和销项发票
     * @author yanglei
     * @date 2023/2/3 9:41
     * @param validateDataDTO 校验的数据
     */
    private void validateFundData(ValidateDataDTO validateDataDTO) throws XbbException {
        JSONObject data = validateDataDTO.getData();
        String corpid = validateDataDTO.getCorpid();
        Integer distributorMark = validateDataDTO.getDistributorMark();
        JSONArray paymentSheetArray = formatPaymentSheetOrPaymentArray(FastJsonHelper.getJsonArrFromFormData(data, RefundEnum.PAYMENT_SHEETS.getAttr()),XbbRefTypeEnum.PAYMENT_SHEET.getCode());
        JSONArray paymentArray = formatPaymentSheetOrPaymentArray(FastJsonHelper.getJsonArrFromFormData(data, RefundEnum.PAYMENTS.getAttr()),XbbRefTypeEnum.PAYMENT.getCode());
        Long contractId = FastJsonHelper.getLongFromFormData(data, RefundEnum.CONTRACT_ID.getAttr());
        boolean fromApproval = Objects.nonNull(validateDataDTO.getTaskId());
        //应收款校验
        if (CollectionsUtil.isNotEmpty(paymentArray)){
            PaasFormEntity paymentFormEntity = paasFormModel.getByBusinessType4Distributor(XbbRefTypeEnum.PAYMENT.getCode(), corpid, distributorMark, null);
            FormDataAddDTO formDataAddDTO = new FormDataAddDTO();
            BeanUtil.copyProperties(validateDataDTO, formDataAddDTO);
            formDataAddDTO.setSubBusinessType(XbbRefTypeEnum.REFUND.getCode());
            formDataAddDTO.setAppId(paymentFormEntity.getAppId());
            formDataAddDTO.setMenuId(paymentFormEntity.getMenuId());
            formDataAddDTO.setFormId(paymentFormEntity.getId());
            JSONObject paymentData = new JSONObject();
            JSONObject customerData = new JSONObject();
            customerData.put(StringConstant.SAAS_LINK_BUSINESS_ID, data.getString(ContractEnum.LINK_CUSTOMER.getAttr()));
            customerData.put(StringConstant.SAAS_LINK_BUSINESS_NAME, data.getString(ContractEnum.LINK_CUSTOMER_HIDE.getAttr()));
            JSONObject contractData = new JSONObject();
            contractData.put(StringConstant.SAAS_LINK_BUSINESS_ID, contractId == null ? "0" : contractId);
            contractData.put(StringConstant.SAAS_LINK_BUSINESS_NAME, validateDataDTO.getSerialNo());
            paymentData.put(PaymentEnum.CUSTOMER.getAttr(), Collections.singletonList(customerData));
            paymentData.put(PaymentEnum.CONTRACT.getAttr(), Collections.singletonList(contractData));
            paymentData.put(PaymentEnum.ADD_PAYMENT.getAttr(), paymentArray);
            formDataAddDTO.setDataList(paymentData);
            formDataAddDTO.getSaasNeedRedundantAttrPoJo().setParentBusinessType(validateDataDTO.getBusinessType());
            formDataAddDTO.getSaasNeedRedundantAttrPoJo().setParentAmount(data.getDouble(ContractEnum.AMOUNT.getAttr()));
            formDataAddDTO.getSaasNeedRedundantAttrPoJo().setLinkItemFormId(validateDataDTO.getFormId());
            formDataAddDTO.setIsTotalPaymentSheetAmount(false);
            formDataAddDTO.setBusinessType(XbbRefTypeEnum.PAYMENT.getCode());
            paymentAnalyticalService.beforeSaveBatch(formDataAddDTO, fromApproval);
        }
        //回款单校验
        if (CollectionsUtil.isNotEmpty(paymentSheetArray)) {
            PaasFormEntity paymentSheetFormEntity = paasFormModel.getByBusinessType4Distributor(XbbRefTypeEnum.PAYMENT_SHEET.getCode(), corpid, distributorMark, null);
            FormDataAddDTO paymentSheetAddDTO = new FormDataAddDTO();
            BeanUtil.copyProperties(validateDataDTO, paymentSheetAddDTO);
            paymentSheetAddDTO.setAppId(paymentSheetFormEntity.getAppId());
            paymentSheetAddDTO.setMenuId(paymentSheetFormEntity.getMenuId());
            paymentSheetAddDTO.setFormId(paymentSheetFormEntity.getId());
            JSONObject paymentSheetData = new JSONObject();
            JSONObject customerData = new JSONObject();
            customerData.put(StringConstant.SAAS_LINK_BUSINESS_ID, data.getString(ContractEnum.LINK_CUSTOMER.getAttr()));
            customerData.put(StringConstant.SAAS_LINK_BUSINESS_NAME, data.getString(ContractEnum.LINK_CUSTOMER_HIDE.getAttr()));
            JSONObject contractData = new JSONObject();
            contractData.put(StringConstant.SAAS_LINK_BUSINESS_ID, contractId == null ? "0" : contractId);
            contractData.put(StringConstant.SAAS_LINK_BUSINESS_NAME, validateDataDTO.getSerialNo());
            paymentSheetData.put(PaymentSheetEnum.CUSTOMER_ID.getAttr(), Collections.singletonList(customerData));
            paymentSheetData.put(PaymentSheetEnum.CONTRACT.getAttr(), Collections.singletonList(contractData));
            if (CollectionsUtil.isNotEmpty(paymentSheetArray)) {
                paymentSheetData.put("addPaymentSheet", paymentSheetArray);
                paymentSheetAddDTO.setDataList(paymentSheetData);
                paymentSheetAddDTO.getSaasNeedRedundantAttrPoJo().setParentBusinessType(validateDataDTO.getBusinessType());
                paymentSheetAddDTO.getSaasNeedRedundantAttrPoJo().setParentAmount(data.getDouble(ContractEnum.AMOUNT.getAttr()));
                paymentSheetAddDTO.getSaasNeedRedundantAttrPoJo().setLinkItemFormId(validateDataDTO.getFormId());
                paymentSheetAddDTO.setBusinessType(XbbRefTypeEnum.PAYMENT_SHEET.getCode());
                paymentSheetAnalyticalService.beforeSaveBatch(paymentSheetAddDTO, PaymentSheetTypeEnum.WRITE_OFF, data.getLongValue(ContractEnum.LINK_CUSTOMER.getAttr()), fromApproval);
            }
        }
        //TODO 发票校验
    }

    /**
     * @description 获取回款单和应收款校验所需的数据格式
     * @author yanglei
     * @date 2023/2/2 15:46
     * @param dataArray 批量data数据
     * @return JSONArray
     */
    private JSONArray formatPaymentSheetOrPaymentArray(JSONArray dataArray,Integer businessType){
        JSONArray result = new JSONArray();
        if (CollectionsUtil.isNotEmpty(dataArray)){
            for (Object o : dataArray) {
                JSONObject data = (JSONObject) o;
                JSONObject json = new JSONObject();
                //应收款状态需要转成对象
                if(Objects.equals(businessType,XbbRefTypeEnum.PAYMENT.getCode())){
                    Object statusObj = data.get(PaymentEnum.STATUS.getAttr());
                    if (statusObj instanceof String){
                        JSONObject statusJson = new JSONObject();
                        statusJson.put("value",statusObj);
                        statusJson.put("text", PaymentStatusEnum.getByCode(statusObj.toString()).getAlias());
                        data.put(PaymentEnum.STATUS.getAttr(),statusJson);
                    }
                }
                json.put("data",data);
                json.put("dataId",data.getLongValue("dataId"));
                json.put("ownerId",data.getJSONArray("ownerId"));
                json.put("coUserId",data.getJSONArray("coUserId"));
                json.put("serialNo",data.getString("serialNo"));
                json.put("uuid",data.getString("uuid"));
                result.add(json);
            }
        }
        return result;
    }


    private void validateDataProduct(JSONArray productArray, String corpid, Long contractId, Long refundId) throws XbbException {
        Set<Long> pageProductIds = new HashSet<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        Map<String,Double> productNumMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        // 是否需要合并
        boolean needMerge = false;
        for (int i = 0; i < productArray.size(); i++) {
            JSONObject productObj = productArray.getJSONObject(i);
            Long refProductId = productObj.getLong(BusinessConstant.REF_PRODUCT_ID);
            if (Objects.isNull(refProductId)) {
                needMerge = true;
                break;
            }
        }
        for (Object object:productArray) {
            JSONObject jsonObject = (JSONObject) object;
            Long productId = jsonObject.getLong(SelectProductEnum.PRODUCT.getAttr());
            pageProductIds.add(productId);
            Double productNum = jsonObject.getDouble(SelectProductEnum.NUM.getAttr());
            String key;
            if (needMerge) {
                key = productId.toString();
            } else {
                Long refProductId = jsonObject.getLong(BusinessConstant.REF_PRODUCT_ID);
                key = productId + "_" + refProductId;
            }
            Double num = productNumMap.getOrDefault(key,0D);
            num += productNum;
            productNumMap.put(key,num);
        }
        Map<Long,String> pageProductMap = saasProductHelp.productExit(corpid,new ArrayList<>(pageProductIds));
        //开了退出库，没开退合同
        Map<String,Double> unRefundMap = saasProductHelp.getContractUnRefund(corpid,contractId,refundId,needMerge);

        // 24187 【退货退款】未开启进销存，编辑退货退款提示不正确
        Boolean isJxcUse = paasAppModel.validateAppEnable(null, XbbRefTypeEnum.JXC.getAlias(), SaasMarkEnum.SAAS.getCode(), corpid);
        if (isJxcUse) {
            ProductUtil.stockProductNumLegalCheck(false, unRefundMap,productNumMap,pageProductMap,I18nMessageUtil.getMessage(I18nStringConstant.REFUND_PRODUCT_NUM_ERROR));
        }
    }

    /**
     * 金额校验
     *
     * @param corpid       公司id
     * @param refundAmount 退款金额
     * @param returnAmount 退货金额
     * @param contractId   公司id
     * @param refundId     退货单id
     * @throws XbbException 异常
     */
    private void refundAmountJudgement(String corpid, Double refundAmount, Double returnAmount, Long contractId, Long refundId, String serialNo) throws XbbException {
        if (refundAmount < BasicConstant.ZERO) {
            throw new XbbException(RefundErrorCodeEnum.API_ERROR_215022);
        }
        if (returnAmount < BasicConstant.ZERO) {
            throw new XbbException(RefundErrorCodeEnum.API_ERROR_215023);
        }
        if (refundAmount > returnAmount) {
            throw new XbbException(RefundErrorCodeEnum.API_ERROR_215020);
        }
        ContractEntityExt contractEntityExt = contractModel.getByKey(contractId, corpid);
        Map<String, Object> param = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        param.put(ParameterConstant.CORPID, corpid);
        param.put(ParameterConstant.DEL, DelEnum.NORMAL.getDel());
        param.put(ParameterConstant.FLOW_STATUS_IN, Arrays.asList(FlowStatusEnum.NOT_NEED_APPROVAL.getType(), FlowStatusEnum.APPROVAL_PENDING.getType(), FlowStatusEnum.PASS.getType(), FlowStatusEnum.IN_APPROVAL.getType()));
        //param.put(ParameterConstant.NEG_ID, refundId);
        List<PaasFormDataEntityExt> paasFormDataEntityExts = paasEsModel.selectByOneCondition(XbbRefTypeEnum.REFUND.getCode(), RefundEnum.CONTRACT_ID.getAttr(), contractId, param, IndexTypeEnum.IDX_SAAS_REFUND);
        //退货金额合计
        Double returnAmountSum = returnAmount;
        for (PaasFormDataEntityExt refund : paasFormDataEntityExts) {
            // 这里得用refundid去判断  原先是用序列号  序列号是可改的  在审批中修改的话就审批不通过了
            if(!Objects.equals(refundId, refund.getDataId())){
                returnAmountSum = Arith.add(returnAmountSum, FastJsonHelper.getDoubleOrDefaultFromFormData(refund.getData(), RefundEnum.RETURN_AMOUNT.getAttr(), BasicConstant.ZERO_DOUBLE));
            }
        }
        Double contractAmount = FastJsonHelper.getDoubleOrDefaultFromFormData(contractEntityExt.getData(), ContractEnum.AMOUNT.getAttr(), BasicConstant.ZERO_DOUBLE);
        if (Arith.compare(contractAmount, returnAmountSum) < BasicConstant.ZERO_DOUBLE) {
            throw new XbbException(RefundErrorCodeEnum.API_ERROR_215005);
        }
    }
}
